#include "sever.h"

#define IP "192.168.50.193"
#define PORT 9090
Client clients[100];  // 存储最大数量
int client_count = 0; // 记录登陆的人数
/* ----------------------------dan人猜数字--------------------------------- */
void startGame(int client_fd, int *secret_number)
{
    MSG response;
    sprintf(response.buf, "游戏开始，请猜一个1到100之间的数字");
    write(client_fd, &response, sizeof(response));
    *secret_number = rand() % 100 + 1;
}
void guessNumber(int client_fd, int secret_number, int guess)
{
    MSG response;
    if (guess < secret_number)
    {
        sprintf(response.buf, "猜低了");
    }
    else if (guess > secret_number)
    {
        sprintf(response.buf, "猜高了");
    }
    else
    {
        sprintf(response.buf, "猜对了");
    }
    write(client_fd, &response, sizeof(response));
}
/* ---------------------------------------------------------=*/
unsigned int szIPToInt(char *pIP) // 把字符串IP转为网络字节序整数IP
{
    unsigned int ip;
    inet_pton(AF_INET, pIP, &ip); // 把字符串IP转成数字IP
    return ip;
}

char *intIPToStr(unsigned int ip) // 把网络字节序整数IP转为字符串IP
{
    char *szIP = malloc(16);
    inet_ntop(AF_INET, &ip, szIP, 16);
    printf("%s\n", szIP);
    return szIP;
}

struct sockaddr_in getAddr(char *pszIp, uint16_t port) // 输入IP和端口，返回一个地址结构体
{
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;               // IPV4地址族
    addr.sin_addr.s_addr = szIPToInt(pszIp); // IP地址
    addr.sin_port = htons(port);             // 端口号，要转成大端字节序
    return addr;
}
// 插入注册信息到数据库的表中
int Insert_info(RG *rn, sqlite3 *db, int i)
{
    char sp_buf[512];
    sprintf(sp_buf, "INSERT INTO UserInfo VALUES('%s', '%s', '%s', '%s');", rn->account, rn->password, rn->name, rn->phone);
    char *errmsg = 0;
    int rc = sqlite3_exec(db, sp_buf, 0, 0, &errmsg);

    MSG response;
    if (rc == SQLITE_OK)
    {
        strcpy(response.buf, "注册成功");
    }
    else
    {
        strcpy(response.buf, "注册失败");
    }
    write(i, &response, sizeof(response));
}

void CheckLogin(RG *rn, sqlite3 *db, int i)
{
    char **result;
    char *errmsg = 0;
    char sp_buf[512];
    int rc, row, col;
    sprintf(sp_buf, "SELECT * FROM UserInfo WHERE Account='%s' AND Password='%s';", rn->account, rn->password);
    rc = sqlite3_get_table(db, sp_buf, &result, &row, &col, &errmsg);
    MSG response;
    if (rc == SQLITE_OK && row > 0)
    {
        strcpy(response.buf, "登录成功");
        response.type = 101;
        // 更新客户端列表
        if (client_count < 100)
        {
            clients[client_count].fd = i;
            strcpy(clients[client_count].account, rn->account);
            client_count++;
        }
        else
        {
            printf("客户端列表已满\n");
        }
    }
    else
    {
        strcpy(response.buf, "账号或密码错误");
        response.type = 102;
    }
    write(i, &response, sizeof(response));
    sqlite3_free_table(result);
}
void FindPassword(RG *rn, sqlite3 *db, int i)
{
    char *errmsg = 0;
    char sp_buf[512];
    char **result;
    int rc, row, col;
    sprintf(sp_buf, "SELECT Password FROM UserInfo WHERE Account='%s' AND Phone='%s';", rn->account, rn->phone);
    rc = sqlite3_get_table(db, sp_buf, &result, &row, &col, &errmsg);
    MSG response;
    if (rc == SQLITE_OK && row > 0)
    {
        strcpy(response.buf, result[1]);
    }
    else
    {
        strcpy(response.buf, "你输入的信息有误或者账号未注册");
    }
    sqlite3_free_table(result);
    write(i, &response, sizeof(response));
}

void AddFriend(ADD_FRI *rn, sqlite3 *db, int i)
{
    char **result;
    char sp_buf[521];
    int rc, row, col;
    char *errmsg = 0;
    MSG response;
    // 检查要添加的人是否存在
    sprintf(sp_buf, "SELECT * FROM UserInfo WHERE Account='%s';", rn->friend_name);
    rc = sqlite3_get_table(db, sp_buf, &result, &row, &col, &errmsg);
    if (rc != SQLITE_OK || errmsg != NULL)
    {
        response.type = 402; // 失败响应类型
        strcpy(response.buf, "你要添加的人不存在");
        write(i, &response, sizeof(response));
        sqlite3_free_table(result); // 释放表格内存
        return;
    }
    // 确保好友存在
    if (row == 0)
    {
        response.type = 402; // 失败响应类型
        strcpy(response.buf, "你要添加的人不存在");
        write(i, &response, sizeof(response));
        sqlite3_free_table(result); // 释放表格内存
        return;
    }
    // 创建好友列表表格
    char tablename[128];
    sprintf(tablename, "%s_friends", rn->self_name);
    sprintf(sp_buf, "CREATE TABLE IF NOT EXISTS \"%s\"(FriendName VARCHAR(128));", tablename);
    rc = sqlite3_exec(db, sp_buf, 0, 0, &errmsg);
    if (rc != SQLITE_OK)
    {
        response.type = 402; // 失败响应类型
        printf("创建好友列表失败:%s", errmsg);
        write(i, &response, sizeof(response));
        return;
    }
    printf("添加好友请求：%s 添加 %s\n", rn->self_name, rn->friend_name); // 添加日志
    // 加入表格
    sprintf(sp_buf, "INSERT INTO \"%s\" VALUES ('%s');", tablename, rn->friend_name);
    rc = sqlite3_exec(db, sp_buf, 0, 0, &errmsg);
    if (rc == SQLITE_OK)
    {
        // 发送添加好友成功信息
        response.type = 401;
        strcpy(response.buf, "添加好友成功");
    }
    else
    {
        // 发送失败信息
        response.type = 402;
        strcpy(response.buf, "添加失败");
    }
    write(i, &response, sizeof(response));
}

void DeleteFriend(ADD_FRI *rn, sqlite3 *db, int i)
{
    char **result;
    char sp_buf[521];
    int rc, row, col;
    char *errmsg = 0;
    MSG response;
    char tablename[128];

    sprintf(tablename, "%s_friends", rn->self_name);
    // 检查要删的好友是否存在
    sprintf(sp_buf, "SELECT 1 FROM \"%s\" WHERE FriendName='%s';", tablename, rn->friend_name);
    rc = sqlite3_get_table(db, sp_buf, &result, &row, &col, &errmsg);
    // printf("删除好友请求：%s 删除 %s\n", rn->self_name, rn->friend_name); // 添加日志
    if (rc != SQLITE_OK)
    {
        response.type = 201; // 失败响应类型
        strcpy(response.buf, "你要删除的好友不存在");
        write(i, &response, sizeof(response));
        sqlite3_free_table(result); // 释放表格内存
        return;
    }
    // 确保好友存在
    if (row == 0)
    {
        response.type = 202; // 失败响应类型
        strcpy(response.buf, "你要删除的好友不存在");
        write(i, &response, sizeof(response));
        sqlite3_free_table(result); // 释放表格内存
        return;
    }
    printf("删除好友请求ssss：%s 删除 %s\n", rn->self_name, rn->friend_name); // 添加日志
    // 删除操作
    sprintf(sp_buf, "DELETE FROM \"%s\" WHERE FriendName='%s';", tablename, rn->friend_name);
    rc = sqlite3_exec(db, sp_buf, 0, 0, &errmsg);
    if (rc == SQLITE_OK)
    {
        response.type = 201;
        strcpy(response.buf, "删除成功");
    }
    else
    {
        response.type = 202;
        strcpy(response.buf, "删除失败");
    }
    write(i, &response, sizeof(response));
}

void ChangePassword(DA *rn, sqlite3 *db, int i)
{
    char **result;
    char sp_buf[521];
    int rc;
    char *errmsg = 0;
    MSG response;
    sprintf(sp_buf, "UPDATE UserInfo SET Password='%s' WHERE Account='%s';", rn->password, rn->account);
    rc = sqlite3_exec(db, sp_buf, 0, 0, &errmsg);
    if (rc == SQLITE_OK)
    {
        response.type == 301;
        strcpy(response.buf, "密码修改成功");
    }
    else
    {
        response.type = 302;
        strcpy(response.buf, "密码修改失败");
    }
    write(i, &response, sizeof(response));
}

void DeleteAccount(DA *rn, sqlite3 *db, int i)
{
    char **result;
    char sp_buf[521];
    int rc, row, col;
    char *errmsg = 0;
    MSG response;
    sprintf(sp_buf, "SELECT * FROM UserInfo WHERE Account='%s'AND Password='%s';", rn->account, rn->password);
    rc = sqlite3_get_table(db, sp_buf, &result, &row, &col, &errmsg);
    if (rc == SQLITE_OK && row > 0)
    {
        // 删除操作
        sprintf(sp_buf, "DELETE FROM UserInfo WHERE Account='%s';", rn->account);
        rc = sqlite3_exec(db, sp_buf, 0, 0, &errmsg);
        if (rc == SQLITE_OK)
        {
            response.type = 501;
            strcpy(response.buf, "账户注销成功");
            char spp_buf[512];
            sprintf(spp_buf, "DROP TABLE IF EXISTS %s_friends;", rn->account);
            rc = sqlite3_exec(db, spp_buf, 0, 0, &errmsg);
            if (rc == SQLITE_OK)
            {
                printf("好友列表删除成功\n");
            }
            else
            {
                printf("好友列表删除失败\n");
            }
        }
        else
        {
            response.type = 502;
            strcpy(response.buf, "账户注销失败");
        }
    }
    else
    {
        response.type = 503;
        strcpy(response.buf, "账号或密码错误");
    }
    sqlite3_free_table(result);
    write(i, &response, sizeof(response));
}

void handleClientDisconnection(int fd) // 有人退出就将他从登录数组中删掉
{
    int index = -1;
    for (int i = 0; i < client_count; i++)
    {
        if (clients[i].fd == fd)
        {
            index = i;
            break;
        }
    }
    if (index != -1)
    {
        for (int j = index; j < client_count - 1; j++)
        {
            clients[j] = clients[j + 1];
        }
        client_count--;
    }
}
void PrintInfo(MSG msg, sqlite3 *db, int i)
{
    char **result;
    char sp_buf[512];
    int rc, row, col;
    char *errmsg = 0;
    sprintf(sp_buf, "SELECT *FROM UserInfo WHERE Account='%s';", msg.buf);
    rc = sqlite3_get_table(db, sp_buf, &result, &row, &col, &errmsg);
    MSG response;
    if (rc == SQLITE_OK && row > 0)
    {
        sprintf(response.buf, "Account:%s,Password:%s,Name=%s,Phone=%s\n", result[col], result[col + 1], result[col + 2], result[col + 3]);
        response.type = 403;
    }
    else
    {
        strcpy(response.buf, "获取失败");
        response.type = 404;
    }
    sqlite3_free_table(result);
    write(i, &response, sizeof(response));
}
int main(int argc, const char *argv[])
{
    /* 数据库操作部分 */
    sqlite3 *db = NULL;
    int data = -1;
    data = sqlite3_open("game.db", &db); // 打开指定的数据库文件，如果不存在将创建一个同名的数据库文件
    if (data < 0)
    {
        printf("创建数据库失败:%s\n", sqlite3_errmsg(db)); // 创建失败
        return -1;
    }
    else
    {
        printf("创建数据库成功\n"); // 创建成功
    }
    char *msg = NULL;
    char sql[] = "CREATE TABLE UserInfo(Account varchar(255),Password varchar(255),Name varchar(255),Phone varchar(255));";
    int ret = sqlite3_exec(db, sql, 0, 0, &msg);
    if (ret != SQLITE_OK)
    {
        printf("创建表失败: %s\n", msg);
    }
    else
    {
        printf("创建表成功\n");
    }
    /* 套接字部分 */
    struct sockaddr_in addr = getAddr(IP, PORT);
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    int val = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(addr));
    if (-1 == bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
    {
        printf("绑定地址失败\n");
        return 0;
    }
    if (-1 == listen(fd, 20))
    {
        printf("监听已超上限\n");
        return 0;
    }

    printf("等待客户端连接...\n");

    /* I/O复用部分 */
    int maxFd = fd;
    fd_set set;
    fd_set old_set;   // 备份原来的套接字集合，因为select喜欢删掉没有发生事件的套接字
    FD_ZERO(&set);    // 清空集合
    FD_SET(fd, &set); // 把fd加到集合中
    old_set = set;
    int secret_number = 0;
    srand(time(NULL)); // 获取时间随机数
    while (1)
    {
        set = old_set; // 还原所有套接字
        select(maxFd + 1, &set, 0, 0, 0);
        for (size_t i = 3; i < maxFd + 1; i++)
        {
            if (0 != FD_ISSET(i, &set))
            {
                if (i == fd)
                {
                    struct sockaddr_in client_addr;
                    socklen_t len = sizeof(client_addr);
                    int Newfd = accept(i, (struct sockaddr *)&client_addr, &len);
                    maxFd = Newfd;           // 最大套接字变成新的套接字
                    FD_SET(Newfd, &old_set); // 把新的套接字保存到集合中
                    /* clients[client_count].fd = Newfd;
                    clients[client_count].addr = client_addr;
                    client_count++; */
                }
                else
                {
                    MSG msg;
                    int ret = read(i, &msg, sizeof(msg)); // 接受从fd上发来的消息
                    if (ret <= 0)                         // 如果read的返回值为0，说明连接的另一半已经退出了
                    {
                        printf("客户端断开连接\n");
                        handleClientDisconnection(i);
                        close(i);
                        FD_CLR(i, &old_set);
                    }
                    else
                    {
                        if (msg.type == 1)
                        {
                            RG *rn = (RG *)msg.buf;
                            Insert_info(rn, db, i);
                        }
                        else if (msg.type == 2)
                        {
                            RG *rn = (RG *)msg.buf;
                            CheckLogin(rn, db, i);
                        }
                        else if (msg.type == 3)
                        {
                            RG *rn = (RG *)msg.buf;
                            FindPassword(rn, db, i);
                        }
                        else if (msg.type == 4)
                        {
                            ADD_FRI *rn = (ADD_FRI *)msg.buf;
                            AddFriend(rn, db, i);
                        }
                        else if (msg.type == 10)
                        {
                            ADD_FRI *rn = (ADD_FRI *)msg.buf;
                            DeleteFriend(rn, db, i);
                        }
                        else if (msg.type == 11)
                        {
                            DA *rn = (DA *)msg.buf;
                            ChangePassword(rn, db, i);
                        }
                        else if (msg.type == 12)
                        {
                            DA *rn = (DA *)msg.buf;
                            DeleteAccount(rn, db, i);
                        }
                        else if (msg.type == 20)
                        {
                            startGame(i, &secret_number);
                        }
                        else if (msg.type == 21)
                        {
                            int guess = atoi(msg.buf);
                            guessNumber(i, secret_number, guess);
                        }
                        else if (msg.type == 5) // 群聊
                        {
                            for (int j = 0; j < client_count; j++)
                            {
                                if (clients[j].fd != i) // 不向发送者发消息
                                {
                                    msg.type = 5;
                                    write(clients[j].fd, &msg, sizeof(msg));
                                    /* printf("转发消息给登录的fd为%s用户,内容是：%s\n", clients[j].account, msg.buf); */
                                }
                            }
                        }
                        else if (msg.type == 6) // 私聊
                        {
                            SIG_CHAT *sc = (SIG_CHAT *)msg.buf;
                            for (size_t j = 0; j < client_count; j++)
                            {
                                if (strcmp(sc->destName, clients[j].account) == 0)
                                {
                                    msg.type = 6;
                                    write(clients[j].fd, &msg, sizeof(MSG));
                                    break;
                                }
                            }
                        }
                        else if (msg.type == 8) // 群聊退出消息
                        {
                            printf("客户端退出群聊\n");
                        }
                        else if (msg.type == 9) // 私聊退出消息
                        {
                            SIG_CHAT *sc = (SIG_CHAT *)msg.buf;
                            printf("客户端%s退出私聊\n", sc->destName);
                        }
                        else if (msg.type == 7)
                        {
                            printf("%s\n", msg.buf);
                            PrintInfo(msg, db, i);
                        }
                    }
                }
            }
        }
    }

    sqlite3_close(db);
    close(fd);
    return 0;
}